package com.wooming.myserver.service.impl;

import com.wooming.myserver.constant.*;
import com.wooming.myserver.dto.*;
import com.wooming.myserver.mapper.GameDataMapper;
import com.wooming.myserver.service.inter.GameRunningService;
import com.wooming.myserver.util.Cost;
import com.wooming.myserver.util.PercentRandom;
import com.wooming.myserver.vo.CostVO;
import com.wooming.myserver.vo.CycleVO;
import com.wooming.myserver.vo.TurnVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 游戏运行服务实现类
 *
 * @author Wooming 2025/05/27
 */
@Service
public class GameRunningServiceImpl implements GameRunningService {

    private final Random random = new Random(System.currentTimeMillis());
    private final GameDataMapper gameDataMapper;

    @Autowired
    public GameRunningServiceImpl(GameDataMapper gameDataMapper) {
        this.gameDataMapper = gameDataMapper;
    }

    @Override
    public boolean moduleLevelUp(Integer userId, String moduleName) {
        // 获取用户游戏数据
        GameDataDTO gameData = gameDataMapper.getGameData(userId);
        GameStatusDTO moduleStatus = gameDataMapper.getModuleStatus(userId, moduleName);
        String frameworkModuleName = moduleName.startsWith("Front") ?
                ModuleName.FRONT_FRAMEWORK.getName() :
                ModuleName.BACK_FRAMEWORK.getName();
        GameStatusDTO frameworkStatus = gameDataMapper.getModuleStatus(userId, frameworkModuleName);

        // 判断是否满足升级条件
        // 计算所需资源
        Cost cost = Cost.getCost(moduleStatus, frameworkStatus);
        // 判断资源是否充足
        if (gameData.getGold() < cost.goldCost() || gameData.getActionPoint() < cost.actionCost()) {
            return false;
        }

        // 升级
        gameData.setGold(gameData.getGold() - cost.goldCost());
        gameData.setActionPoint(gameData.getActionPoint() - cost.actionCost());
        moduleStatus.setCurrentLevel(moduleStatus.getCurrentLevel() + 1);

        gameDataMapper.updateGameData(gameData);
        gameDataMapper.updateGameStatus(moduleStatus);
        return true;
    }

    @Override
    public CostVO nextLevelCost(Integer userId, String moduleName) {
        // 获取用户游戏数据
        GameStatusDTO moduleStatus = gameDataMapper.getModuleStatus(userId, moduleName);
        String frameworkModuleName = moduleName.startsWith("Front") ?
                ModuleName.FRONT_FRAMEWORK.getName() :
                ModuleName.BACK_FRAMEWORK.getName();
        GameStatusDTO frameworkStatus = gameDataMapper.getModuleStatus(userId, frameworkModuleName);

        // 计算所需资源
        Cost cost = Cost.getCost(moduleStatus, frameworkStatus);

        return new CostVO(
                moduleName,
                cost.goldCost(),
                cost.actionCost()
        );
    }

    @Override
    public boolean stageUp(Integer userId) {
        // 获取用户游戏数据
        GameDataDTO gameData = gameDataMapper.getGameData(userId);

        // 判断条件
        if (gameData.getLevel() == GameConst.MAX_STAGE.getValue()) {
            return false;
        } else if (gameData.getGold() < GameStageConst.STAGE_UP_NEED_GOLD.getValue()[gameData.getLevel() - 1] ||
                gameData.getActionPoint() < GameStageConst.STAGE_UP_NEED_ACTION.getValue()[gameData.getLevel() - 1] ||
                gameData.getTraffic() < GameStageConst.STAGE_UP_NEED_TRAFFIC.getValue()[gameData.getLevel() - 1] ||
                gameData.getTurn() < GameStageConst.STAGE_UP_NEED_TURN.getValue()[gameData.getLevel() - 1]
        ) {
            return false;
        } else {
            // 消耗资源
            gameData.setGold(gameData.getGold() - GameStageConst.STAGE_UP_COST_GOLD.getValue()[gameData.getLevel() - 1]);
            gameData.setActionPoint(gameData.getActionPoint() - GameStageConst.STAGE_UP_COST_ACTION.getValue()[gameData.getLevel() - 1]);
            // 升级
            gameData.setLevel(gameData.getLevel() + 1);
            // 更新人力数据
            List<HumanResourceDTO> humanResourceList =
                    gameDataMapper.getHumanResource(userId).stream()
                            .peek(humanResourceDTO -> {
                                humanResourceDTO.setMaxLevel(GameStageConst.HUMAN_RESOURCE_MAX_LEVEL.getValue()[gameData.getLevel() - 1]);
                                humanResourceDTO.setTrainCost(GameStageConst.HUMAN_RESOURCE_TRAIN_COST_EACH_LEVEL.getValue()[gameData.getLevel() - 1]);
                                humanResourceDTO.setSalary(GameStageConst.HUMAN_RESOURCE_SALARY_EACH_LEVEL.getValue()[gameData.getLevel() - 1]);
                                humanResourceDTO.setActionPoint(GameStageConst.HUMAN_RESOURCE_ACTION_POINT_EACH_LEVEL.getValue()[gameData.getLevel() - 1]);
                            })
                            .toList();
            // 更新数据
            gameDataMapper.updateGameData(gameData);
            humanResourceList.forEach(gameDataMapper::updateHumanResource);
            return true;
        }
    }

    /**
     * 整个项目最费人的地方...
     * 回合演算
     *
     * @param turnDTO 回合数据
     * @return 回合结果
     */
    @Override
    public TurnVO turn(TurnDTO turnDTO) {
        /* 回合结算顺序:
         * 1.事件触发
         * 2.宣发影响倍率
         * 3.风评变更
         * 4.周期结算
         * 5.资源结算与数据更新
         * 6.打包返回结果
         */
        // 获取数据
        GameDataDTO gameDataDTO = gameDataMapper.getGameData(turnDTO.getUserId());
        List<HumanResourceDTO> humanResourceList = gameDataMapper.getHumanResource(turnDTO.getUserId());
        List<GameStatusDTO> gameStatusList = gameDataMapper.getGameStatus(turnDTO.getUserId());
        TotalDTO totalDTO = gameDataMapper.getTotal(turnDTO.getUserId());

        // 构建回合结果
        TurnVO turnVO = new TurnVO();
        turnVO.setEvent(new ArrayList<>());
        turnVO.setHappenedRank(new ArrayList<>());

        // 回合新增
        gameDataDTO.setTurn(gameDataDTO.getTurn() + 1);

        /* 事件触发 */
        // 受击事件
        boolean isAttack = false;
        if (gameDataDTO.getTurn() > GameConst.NEW_USER_PROTECT_TURN.getValue()) { // 已过新手保护期
            // 优先级:DDos>SQL>XSS
            // 概率为:基本+2*每回合+人流/100-优化概率*对应安全模块等级
            double base = GameMultiplier.ATTACK_BASE_PROBABILITY.getValue() +
                    gameDataDTO.getTurn() * GameMultiplier.RISK_PROBABILITY_INCREASE.getValue() +
                    gameDataDTO.getTraffic() * GameMultiplier.TRAFFIC_PROBABILITY_MULTIPLIER.getValue();
            double DDoS = base - GameMultiplier.MODULE_LEVEL_PROBABILITY_DECREASE.getValue() * gameDataMapper.getModuleStatus(turnDTO.getUserId(), ModuleName.SECURITY_DDOS.getName()).getCurrentLevel();
            double SQL = base - GameMultiplier.MODULE_LEVEL_PROBABILITY_DECREASE.getValue() * gameDataMapper.getModuleStatus(turnDTO.getUserId(), ModuleName.SECURITY_SQL.getName()).getCurrentLevel();
            double XSS = base - GameMultiplier.MODULE_LEVEL_PROBABILITY_DECREASE.getValue() * gameDataMapper.getModuleStatus(turnDTO.getUserId(), ModuleName.SECURITY_XSS.getName()).getCurrentLevel();
            if (PercentRandom.trueRandom(DDoS)) {
                turnVO.getEvent().add(EventName.ATTACK_DDOS.getName());
                isAttack = true;
            } else if (PercentRandom.trueRandom(SQL)) {
                turnVO.getEvent().add(EventName.ATTACK_SQL.getName());
                isAttack = true;
            } else if (PercentRandom.trueRandom(XSS)) {
                turnVO.getEvent().add(EventName.ATTACK_XSS.getName());
                isAttack = true;
            } else {
                turnVO.getEvent().add(EventName.NORMAL.getName());
            }
        } else {
            turnVO.getEvent().add(EventName.NORMAL.getName());
        }
        // 设置发生位
        Integer rank = random.nextInt(1, GameConst.TURN_PER_CYCLE.getValue() + 1);
        turnVO.getHappenedRank().add(rank);

        // 其他事件
        if (PercentRandom.trueRandom(GameMultiplier.OTHER_EVENT_PROBABILITY.getValue())) {
            turnVO.getEvent().add(EventName.ATTENTION.getName());
        } else if (PercentRandom.trueRandom(GameMultiplier.OTHER_EVENT_PROBABILITY.getValue())) {
            turnVO.getEvent().add(EventName.HIT.getName());
        } else {
            turnVO.getEvent().add(EventName.NORMAL.getName());
        }
        // 设置发生位
        turnVO.getHappenedRank().add(random.nextInt(1, GameConst.TURN_PER_CYCLE.getValue() + 1));

        /* 宣发倍率 */
        double publicityMultiplier = 1;
        if (gameDataDTO.getLevel() == 3) {  // 用户达到第三阶段
            publicityMultiplier += turnDTO.getPublicityCost() * GameMultiplier.PUBLICITY_COST_MULTIPLIER_ADD.getValue();
        }

        /* 风评变化 */
        double swing = random.nextDouble(-GameMultiplier.REPUTATION_FLOAT.getValue(), GameMultiplier.REPUTATION_FLOAT.getValue());
        double reputationChange = swing
                // 前端UI等级增益
                + GameMultiplier.FRONT_UI_LEVEL_REPUTATION_INCREASE.getValue() * gameDataMapper.getModuleStatus(turnDTO.getUserId(), ModuleName.FRONT_UI.getName()).getCurrentLevel()
                // 后端速度等级增益
                + GameMultiplier.BACK_SPEED_LEVEL_REPUTATION_INCREASE.getValue() * gameDataMapper.getModuleStatus(turnDTO.getUserId(), ModuleName.BACK_SPEED.getName()).getCurrentLevel()
                // 回合减益
                - GameMultiplier.REPUTATION_DECREASE_PER_TURN.getValue() * gameDataDTO.getTurn();

        // 事件影响
        // 攻击事件
        if (turnVO.getEvent().contains(EventName.ATTACK_DDOS.getName()))
            reputationChange -= GameMultiplier.DDOS_REPUTATION_INFLUENCE.getValue() * random.nextDouble(0.5, 1);
        else if (turnVO.getEvent().contains(EventName.ATTACK_XSS.getName()))
            reputationChange -= GameMultiplier.XSS_REPUTATION_INFLUENCE.getValue() * random.nextDouble(0.5, 1);
        // 受关注事件
        if (turnVO.getEvent().contains(EventName.ATTENTION.getName()))
            reputationChange *= GameMultiplier.ATTENTION_MULTIPLIER.getValue();
        // 宣发影响
        reputationChange *= publicityMultiplier;
        double reputation = gameDataDTO.getReputation() + reputationChange;
        // 限定范围
        if (reputation > GameConst.MAX_REPUTATION.getValue()) reputation = GameConst.MAX_REPUTATION.getValue();
        else if (reputation < 0) reputation = 0;
        // 更改风评
        gameDataDTO.setReputation(reputation);
        // 记录变化
        turnVO.setReputationChange(reputationChange);

        /* 周期结算 */
        // 数据暂存(生拷贝)
        GameDataDTO temp = new GameDataDTO();
        temp.setTraffic(gameDataDTO.getTraffic());
        temp.setAvgConsumption(gameDataDTO.getAvgConsumption());
        // 生成周期数据
        List<CycleVO> cycleVOList = new ArrayList<>();
        for (int i = 0; i < GameConst.TURN_PER_CYCLE.getValue(); i++) {
            CycleVO cycleVO = cycle(
                    i + 1,
                    publicityMultiplier,
                    turnVO,
                    gameDataDTO
            );
            cycleVOList.add(cycleVO);
        }
        // 记录周期数据
        turnVO.setCyclesData(cycleVOList);

        /* 资源结算与更新 */
        // 记录总变化
        // 人流
        turnVO.setTotalTrafficChange(
                gameDataDTO.getTraffic() - temp.getTraffic()
        );
        // 人均消费
        turnVO.setTotalAvgConsumptionChange(
                gameDataDTO.getAvgConsumption() - temp.getAvgConsumption()
        );
        // 总营收
        AtomicInteger totalIncome = new AtomicInteger();
        // 周期数据总和
        cycleVOList.forEach(cycleVO -> totalIncome.addAndGet(cycleVO.getGoldGet()));
        // 剩余行动点转化
        totalIncome.addAndGet(gameDataDTO.getActionPoint() * GameConst.ACTION_POINT_CONVERT.getValue());
        gameDataDTO.setActionPoint(0);
        turnVO.setTotalGoldGet(totalIncome.get());
        // 总支出
        // 模块等级之和
        int moduleLevelSum = gameStatusList.stream()
                .mapToInt(GameStatusDTO::getCurrentLevel)
                .sum();
        // 员工总薪资
        int salary = humanResourceList.stream()
                .mapToInt(this::salary)
                .sum();
        int cost = turnDTO.getPublicityCost() // 宣发花费
                // 模块等级维护花费
                + GameConst.MODULE_MAINTAIN_COST_EACH_LEVEL_EACH_TURN.getValue() * moduleLevelSum
                // 员工总薪资
                + salary;
        // 受击消耗
        if (isAttack) cost += GameStageConst.ATTACK_COST_EACH_LEVEL.getValue()[gameDataDTO.getLevel() - 1];
        // 记录
        turnVO.setTotalGoldCost(cost);

        // 最终资源存量
        // 资金(注意溢出)
        int gold = gameDataDTO.getGold() + totalIncome.get() - cost;
        if (gold < -1000000000 || gold > GameConst.MAX_GOLD.getValue()) gold = GameConst.MAX_GOLD.getValue();
        else if (gold < 0) gold = 0;
        gameDataDTO.setGold(gold);

        // 计算下一回合行动点
        int actionPoint = humanResourceList.stream()
                .mapToInt(this::actionPoint)
                .sum();
        gameDataDTO.setActionPoint(actionPoint + GameConst.BASE_ACTION_POINT.getValue());

        // 统计数据
        totalDTO.setTurn(totalDTO.getTurn() + 1);   // 回合数
        totalDTO.setGold(totalDTO.getGold() + totalIncome.get()); // 总营收
        totalDTO.setActionPoint(totalDTO.getActionPoint() + actionPoint + GameConst.BASE_ACTION_POINT.getValue());//  总行动点数
        totalDTO.setTraffic(Math.max(totalDTO.getTraffic(), gameDataDTO.getTraffic())); // 最大流量

        // 更新统计数据
        gameDataMapper.updateTotalData(totalDTO);

        // 更新游戏数据
        turnVO.setGameData(gameDataDTO);
        gameDataMapper.updateGameData(gameDataDTO);

        return turnVO;
    }

    private int salary(HumanResourceDTO humanResourceDTO) {
        return humanResourceDTO.getLevel() * humanResourceDTO.getSalary();
    }

    private int actionPoint(HumanResourceDTO humanResourceDTO) {
        return humanResourceDTO.getLevel() * humanResourceDTO.getActionPoint();
    }

    private CycleVO cycle(
            int rank,
            double publicityMultiplier,
            TurnVO turnVO,
            GameDataDTO gameDataDTO
    ) {
        CycleVO cycleVO = new CycleVO();
        // 序号
        cycleVO.setRank(rank);

        // 风评倍率
        double reputationMultiplier = 1
                + (gameDataDTO.getReputation() - GameMultiplier.REPUTATION_MULTIPLIER_BASE.getValue())
                * GameMultiplier.REPUTATION_TO_REPUTATION_MULTIPLIER.getValue();

        // 判断受攻击周期
        double attackMultiplier = 1;
        boolean isAttacked = false;
        if (
                turnVO.getEvent().contains(EventName.ATTACK_DDOS.getName())
                        && rank >= turnVO.getHappenedRank().get(0)  // DDoS攻击开始
        ) {
            attackMultiplier = GameMultiplier.DDOS_MULTIPLIER.getValue();
            isAttacked = true;
        } else if (
                turnVO.getEvent().contains(EventName.ATTACK_SQL.getName())
                        && rank >= turnVO.getHappenedRank().get(0)  // SQL注入攻击开始
        ) {
            attackMultiplier = GameMultiplier.SQL_MULTIPLIER.getValue();
            isAttacked = true;
        } else if (
                turnVO.getEvent().contains(EventName.ATTACK_XSS.getName())
                        && rank >= turnVO.getHappenedRank().get(0)  // XSS攻击开始
        ) {
            attackMultiplier = GameMultiplier.XSS_MULTIPLIER.getValue();
            isAttacked = true;
        }
        // 判断受关注
        boolean isAttention = turnVO.getEvent().contains(EventName.ATTENTION.getName())
                && rank >= turnVO.getHappenedRank().get(1);
        // 判断风口
        boolean isHit = turnVO.getEvent().contains(EventName.HIT.getName())
                && rank >= turnVO.getHappenedRank().get(1);

        // 人流变化
        double trafficChange =
                // 浮动值
                random.nextDouble(-GameMultiplier.TRAFFIC_FLOAT.getValue(), GameMultiplier.TRAFFIC_FLOAT.getValue())
                        // 前端交互模块等级增加
                        + GameMultiplier.FRONT_INTERACT_LEVEL_TRAFFIC_INCREASE.getValue() * gameDataMapper.getModuleStatus(gameDataDTO.getUserId(), ModuleName.FRONT_INTERACT.getName()).getCurrentLevel()
                        // 回合数递减
                        - GameMultiplier.TRAFFIC_DECREASE_PER_TURN.getValue() * gameDataDTO.getTurn();
        // 事件影响
        if (isAttacked) trafficChange *= GameMultiplier.ATTACK_TRAFFIC_INFLUENCE.getValue();
        trafficChange *= reputationMultiplier;
        if (isAttention) trafficChange *= GameMultiplier.ATTENTION_MULTIPLIER.getValue();
        // 限定范围
        int traffic = gameDataDTO.getTraffic() + (int) trafficChange;
        if (traffic > GameConst.MAX_TRAFFIC.getValue()) traffic = GameConst.MAX_TRAFFIC.getValue();
        else if (traffic < GameConst.BASE_TRAFFIC.getValue()) traffic = GameConst.BASE_TRAFFIC.getValue();
        // 记录变化
        cycleVO.setTrafficChange((int) trafficChange);
        // 赋值
        gameDataDTO.setTraffic(traffic);

        // 人均消费变化
        double avgConsumptionChange =
                // 浮动值
                random.nextDouble(-GameMultiplier.PER_PERSON_CONSUME_FLOAT.getValue(), GameMultiplier.PER_PERSON_CONSUME_FLOAT.getValue())
                        // 后端通讯模块等级增加
                        + GameMultiplier.BACK_COMM_LEVEL_PER_PERSON_CONSUME_INCREASE.getValue() * gameDataMapper.getModuleStatus(gameDataDTO.getUserId(), ModuleName.BACK_COMM.getName()).getCurrentLevel()
                        // 回合数递减
                        - GameMultiplier.PER_PERSON_CONSUME_DECREASE_PER_TURN.getValue() * gameDataDTO.getTurn();
        // 事件影响
        if (isAttacked) avgConsumptionChange *= GameMultiplier.ATTACK_PER_PERSON_CONSUME_INFLUENCE.getValue();
        avgConsumptionChange *= reputationMultiplier;
        // 限定范围
        double avgConsumption = gameDataDTO.getAvgConsumption() + avgConsumptionChange;
        if (avgConsumption > GameConst.MAX_PER_PERSON_CONSUME.getValue())
            avgConsumption = GameConst.MAX_PER_PERSON_CONSUME.getValue();
        else if (avgConsumption < GameConst.BASE_AVG_CONSUME.getValue()) avgConsumption = GameConst.BASE_AVG_CONSUME.getValue();
        // 记录变化
        cycleVO.setAvgConsumptionChange(avgConsumptionChange);
        // 赋值
        gameDataDTO.setAvgConsumption(avgConsumption);

        // 营收
        double base = gameDataDTO.getTraffic() * gameDataDTO.getAvgConsumption() * GameMultiplier.BASE_INCOME_MULTIPLIER.getValue();
        int income = (int) (base * attackMultiplier * publicityMultiplier);
        if (isHit) income = (int) (GameMultiplier.HIT_MULTIPLIER.getValue() * income);
        cycleVO.setGoldGet(income);

        // 返回
        return cycleVO;
    }
}
